﻿using Goway.Log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Goway.StackingHelper.Inovance
{
    public class HC_MODBUSTCPV2
    {
        public enum SoftElemType
        {
            //AM600
            ELEM_QX = 0,     //QX元件
            ELEM_MW = 1,     //MW元件
            ELEM_X = 2,      //X元件(对应QX200~QX300)
            ELEM_Y = 3,      //Y元件(对应QX300~QX400)

            //H3U
            REGI_H3U_Y = 0x20,       //Y元件的定义	
            REGI_H3U_X = 0x21,      //X元件的定义							
            REGI_H3U_S = 0x22,      //S元件的定义				
            REGI_H3U_M = 0x23,      //M元件的定义							
            REGI_H3U_TB = 0x24,     //T位元件的定义				
            REGI_H3U_TW = 0x25,     //T字元件的定义				
            REGI_H3U_CB = 0x26,     //C位元件的定义				
            REGI_H3U_CW = 0x27,     //C字元件的定义				
            REGI_H3U_DW = 0x28,     //D字元件的定义				
            REGI_H3U_CW2 = 0x29,        //C双字元件的定义
            REGI_H3U_SM = 0x2a,     //SM
            REGI_H3U_SD = 0x2b,     //
            REGI_H3U_R = 0x2c,      //
                                    //H5u
            REGI_H5U_Y = 0x30,       //Y元件的定义	
            REGI_H5U_X = 0x31,      //X元件的定义							
            REGI_H5U_S = 0x32,      //S元件的定义				
            REGI_H5U_M = 0x33,      //M元件的定义	
            REGI_H5U_B = 0x34,       //B元件的定义
            REGI_H5U_D = 0x35,       //D字元件的定义
            REGI_H5U_R = 0x36,       //R字元件的定义

        }

        #region 标准库
        [DllImport("StandardModbusApi.dll", EntryPoint = "Init_ETH_String", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool Init_ETH_String(string sIpAddr, int nNetId = 0, int IpPort = 502);

        [DllImport("StandardModbusApi.dll", EntryPoint = "Exit_ETH", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool Exit_ETH(int nNetId = 0);


        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Write_Soft_Elem", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Write_Soft_Elem(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);


        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Read_Soft_Elem", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Read_Soft_Elem(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);


        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Read_Device_Block", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Read_Device_Block(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eType">Stacking数据类型</param>
        /// <param name="nStartAddr">开始地址</param>
        /// <param name="nCount">长度</param>
        /// <param name="pValue">字符数组</param>
        /// <param name="nNetId"></param>
        /// <returns></returns>
        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Write_Device_Block", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Write_Device_Block(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stratAddr">起始地址</param>
        /// <param name="length"></param>
        /// <param name="ints"></param>
        /// <returns></returns>
        public static int[] ReadInt16(int stratAddr, int length)
        {
            int[] ints = null;
            //缓冲区。读取整型字元件则一个元件占两个byte，位元件则占一个byte。例如读取D元件500个，则缓冲区大小为1000以上
            try {
                byte[] pBuf = new byte[length*2];
                int nStartAddr = Convert.ToInt32(stratAddr);
                int nCount = Convert.ToInt32(length);
                HC_MODBUSTCPV2.SoftElemType ElemType = HC_MODBUSTCPV2.SoftElemType.REGI_H5U_D;
                int nRet = HC_MODBUSTCPV2.H5u_Read_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
                if (nRet != 1)
                {
                    insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
                    LoggerHelper.Error("读取数据时候通讯异常");
                    return ints;
                }  
                ints = new int[length];
                for (int i = 0; i < nCount; i++)
                {
                    byte[] databuf = new byte[2] { 0, 0 };
                    databuf[0] = pBuf[i * 2];
                    databuf[1] = pBuf[i * 2 + 1];
                    int iTemp = BitConverter.ToInt16(databuf, 0); 
                    ints[i] = iTemp;
                } 

                return ints;
            } catch (Exception ex) { 
                LoggerHelper.Error(ex);
                return ints;
            } 
        }

        public static int[] ReadInt64(int stratAddr, int length)
        {
            int[] ints = null;
            //缓冲区。读取整型字元件则一个元件占两个byte，位元件则占一个byte。例如读取D元件500个，则缓冲区大小为1000以上
            try
            {
                byte[] pBuf = new byte[length * 2];
                int nStartAddr = Convert.ToInt32(stratAddr);
                int nCount = Convert.ToInt32(length);
                HC_MODBUSTCPV2.SoftElemType ElemType = HC_MODBUSTCPV2.SoftElemType.REGI_H5U_D;
                int nRet = HC_MODBUSTCPV2.H5u_Read_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
                if (nRet != 1)
                {
                    insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
                    LoggerHelper.Error("读取数据时候通讯异常");
                    return ints;
                }
                ints = new int[length];
                for (int i = 0; i < nCount; i++)
                {
                    byte[] databuf = new byte[2] { 0, 0 };
                    databuf[0] = pBuf[i * 2];
                    databuf[1] = pBuf[i * 2 + 1];
                    int iTemp = BitConverter.ToInt32(databuf, 0);
                    ints[i] = iTemp;
                }
                return ints;
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(ex);
                return ints;
            }
        }

        public static float[] ReadFlot(int stratAddr, int length)
        {
            float[] ft = null;
            //缓冲区。读取整型字元件则一个元件占两个byte，位元件则占一个byte。例如读取D元件500个，则缓冲区大小为1000以上
            try
            {

                byte[] pBuf = new byte[length * 2];
                int nStartAddr = Convert.ToInt32(stratAddr);
                int nCount = Convert.ToInt32(length);
                HC_MODBUSTCPV2.SoftElemType ElemType = HC_MODBUSTCPV2.SoftElemType.REGI_H5U_D;
                int nRet = HC_MODBUSTCPV2.H5u_Read_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
                if (nRet != 1)
                {
                    insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
                    return ft;
                }
                nCount = nCount / 2;
                ft = new float[nCount];
                for (int i = 0; i < nCount; i++)
                {
                    byte[] databuf = new byte[4] { 0, 0, 0, 0 };
                    databuf[0] = pBuf[i * 4];
                    databuf[1] = pBuf[i * 4 + 1];
                    databuf[2] = pBuf[i * 4 + 2];
                    databuf[3] = pBuf[i * 4 + 3];
                    float fTemp = BitConverter.ToSingle(databuf, 0);
                    ft[i] = fTemp;
                }
                return ft;
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(ex);
                return ft;
            }
        }
        public static byte[] ReadBuf(int stratAddr, int length)
        {
            byte[] pBuf = new byte[length];
            // int[] ints = null;
            //缓冲区。读取整型字元件则一个元件占两个byte，位元件则占一个byte。例如读取D元件500个，则缓冲区大小为1000以上
            try
            {
               
                int nStartAddr = Convert.ToInt32(stratAddr);
                int nCount = Convert.ToInt32(length);
                HC_MODBUSTCPV2.SoftElemType ElemType = HC_MODBUSTCPV2.SoftElemType.REGI_H5U_D;
                int nRet = HC_MODBUSTCPV2.H5u_Read_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
                if (nRet != 1)
                {
                    insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
                   
                }
                return pBuf;
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(ex);
                return pBuf;
            }
        }



        public static int[] ReadDInt(int stratAddr, int length )
        {
            int[] ft = null;
            //缓冲区。读取整型字元件则一个元件占两个byte，位元件则占一个byte。例如读取D元件500个，则缓冲区大小为1000以上
            try
            {
                
                byte[] pBuf = new byte[length * 2];
                int nStartAddr = Convert.ToInt32(stratAddr);
                int nCount = Convert.ToInt32(length); 
                HC_MODBUSTCPV2.SoftElemType ElemType = HC_MODBUSTCPV2.SoftElemType.REGI_H5U_D;
                int nRet = HC_MODBUSTCPV2.H5u_Read_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
                if (nRet != 1)
                {
                    insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
                    return ft;
                } 
                nCount = nCount / 2;
                ft = new int[nCount];
                for (int i = 0; i < nCount; i++)
                {
                            byte[] databuf = new byte[4] { 0, 0, 0, 0 };
                            databuf[0] = pBuf[i * 4];
                            databuf[1] = pBuf[i * 4 + 1];
                            databuf[2] = pBuf[i * 4 + 2];
                            databuf[3] = pBuf[i * 4 + 3];
                            int fTemp = BitConverter.ToInt32(databuf, 0);
                             ft[i] = fTemp;
                     
                }  
                return ft;
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(ex);
                return ft;
            }
        }
        public static int WriteInt16(int stratAddr, int length,int[] invars)
        {
            byte[] pBuf = new byte[length * 2];
            int nStartAddr = Convert.ToInt32(stratAddr);
            int nCount = Convert.ToInt32(length);
            SoftElemType ElemType = SoftElemType.REGI_H5U_D;
            for (int i = 0; i < invars.Length; i++)
            {
                int idata = Convert.ToInt16(invars[i]);
                byte[] dataBuf = new byte[2] { 0, 0 };
                dataBuf = BitConverter.GetBytes(idata);
                pBuf[2 * i] = dataBuf[0];
                pBuf[2 * i + 1] = dataBuf[1];
            }
            int nRet = H5u_Write_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
            if (nRet != 1)
            {
                insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
            }
            return nRet;
        }

        public static int WriteInt32(int stratAddr, int length, int[] invars)
        {
            byte[] pBuf = new byte[length * 2];
            int nStartAddr = Convert.ToInt32(stratAddr);
            int nCount = Convert.ToInt32(length);
            SoftElemType ElemType = SoftElemType.REGI_H5U_D;
            for (int i = 0; i < invars.Length; i++)
            {
                int idata = Convert.ToInt32(invars[i]);
                byte[] dataBuf = new byte[4] { 0, 0, 0, 0 };
                dataBuf = BitConverter.GetBytes(idata);
                pBuf[4 * i] = dataBuf[0];
                pBuf[4 * i + 1] = dataBuf[1];
                pBuf[4 * i + 2] = dataBuf[2];
                pBuf[4 * i + 3] = dataBuf[3];
            }
            int nRet = H5u_Write_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
            if (nRet != 1)
            {
                insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
            }
            return nRet;
        }

        public static int WriteFloat(int stratAddr, int length, float[] invars)
        {
            byte[] pBuf = new byte[length * 2];
            int nStartAddr = Convert.ToInt32(stratAddr);
            int nCount = Convert.ToInt32(length);
            SoftElemType ElemType = SoftElemType.REGI_H5U_D;
            for (int i = 0; i < invars.Length; i++)
            {
                float fdata = Convert.ToSingle(invars[i]);
                byte[] dataBuf = new byte[4] { 0, 0, 0, 0 };
                dataBuf = BitConverter.GetBytes(fdata);
                pBuf[4 * i] = dataBuf[0];
                pBuf[4 * i + 1] = dataBuf[1];
                pBuf[4 * i + 2] = dataBuf[2];
                pBuf[4 * i + 3] = dataBuf[3];
            }
            int nRet = H5u_Write_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
            if (nRet != 1)
            {
                insertNote(DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
            }
            return nRet;
        }

        public static int  Write(int stratAddr, int length, string Type, string invars)
        {
            byte[] pBuf =new byte[length*2];
            int nStartAddr = Convert.ToInt32(stratAddr);
            int nCount = Convert.ToInt32(length);
            bool bIsWord = false;//是否字元件
            SoftElemType ElemType = SoftElemType.REGI_H5U_Y;
            switch (Type) {
                case "Y": 
                ElemType = SoftElemType.REGI_H5U_Y;
                    break; 
                case "X":
             
                ElemType = SoftElemType.REGI_H5U_X;
                    break;
                case "S":
             
                ElemType = SoftElemType.REGI_H5U_S;
                    break;
                case "M":
             
                ElemType = SoftElemType.REGI_H5U_M;
                    break;
                case "B":
             
                ElemType = SoftElemType.REGI_H5U_B;
                    break;
                case "D": 
                bIsWord = true;
                ElemType = SoftElemType.REGI_H5U_D;
                    break;
                case "R":
                bIsWord = true;
                ElemType = SoftElemType.REGI_H5U_R;
                    break;
            }
            var Data = invars.Split(',');
            GetDataFromUI(pBuf, Data, bIsWord, 0);
            int nRet = H5u_Write_Device_Block(ElemType, nStartAddr, nCount, pBuf, 0);
            if (nRet != 1)
            {
                insertNote( DateTime.Now.ToString() + "：ErrorCode " + nRet.ToString() + "\r\n");
            }
            else
            {
               // insertNote( DateTime.Now.ToString() + "写入成功！\r\n");
            }

            return nRet;
        }



        private static void GetDataFromUI(byte[] pBuf, string[] arr, bool bIsWord, int nDataType)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] == string.Empty)
                {
                    break;
                }
                double nVal = Convert.ToDouble(arr[i]);
                if (bIsWord)
                {
                    if (nDataType == 0)//16位整形
                    {
                        int idata = Convert.ToInt16(arr[i]);
                        byte[] dataBuf = new byte[2] { 0, 0 };
                        dataBuf = BitConverter.GetBytes(idata);
                        pBuf[2 * i] = dataBuf[0];
                        pBuf[2 * i + 1] = dataBuf[1];
                    }
                    else if (nDataType == 1)//32位整形
                    {
                        int idata = Convert.ToInt32(arr[i]);
                        byte[] dataBuf = new byte[4] { 0, 0, 0, 0 };
                        dataBuf = BitConverter.GetBytes(idata);
                        pBuf[4 * i] = dataBuf[0];
                        pBuf[4 * i + 1] = dataBuf[1];
                        pBuf[4 * i + 2] = dataBuf[2];
                        pBuf[4 * i + 3] = dataBuf[3];
                    }
                    else if (nDataType == 2)//浮点数
                    {
                        float fdata = Convert.ToSingle(arr[i]);
                        byte[] dataBuf = new byte[4] { 0, 0, 0, 0 };
                        dataBuf = BitConverter.GetBytes(fdata);
                        pBuf[4 * i] = dataBuf[0];
                        pBuf[4 * i + 1] = dataBuf[1];
                        pBuf[4 * i + 2] = dataBuf[2];
                        pBuf[4 * i + 3] = dataBuf[3];
                    }
                }
                else
                {
                    pBuf[i] = (byte)nVal;
                }
            }
        }

        public static void insertNote(string message)
        {
            LoggerHelper.Fatal(message);
        }
    }
}
